﻿using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using DotDiff.TestInterface.Controls;

namespace DotDiff.TestInterface
{
    public partial class Main : Form
    {

        XmlNamespaceManager nsMgr;
        XmlCompare xmlCompare = new XmlCompare();
        private XmlFunctions xmlFunctions;

        public Main()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Load the about box
        /// </summary>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.Show(this);
        }

        private void btnCompare_Click(object sender, EventArgs e)
        {
            if (ntbNew.TextBox.Text == "" || ntbOld.TextBox.Text == "")
            {
                MessageBox.Show("Please load in XML files to compare");
                return;
            }
            RunCompare();
        }

        private void btnCopyAll_Click(object sender, EventArgs e)
        {
            foreach (DiffInstance diffInstance in xmlCompare.Differences)
            {
                xmlCompare.MergeNode(diffInstance);
            }
            xmlCompare.Differences.Clear();
            lblMissing.Text = "";
            lblDifferent.Text = "";
            UpateTextBoxes();
        }

        private void btnCopySelected_Click(object sender, EventArgs e)
        {
            if (xmlCompare.Differences.Count == 0)
            {
                return;
            }

            if (lblSelected.Text == "")
            {
                MessageBox.Show("please select a change to merge, do this by clicking on the right text box");
                return;
            }

            int lineNumber = int.Parse(lblSelected.Text);
            string xpath = xmlFunctions.GetXPath(lineNumber, ntbNew.TextBox.Text);

            foreach (DiffInstance diffInstance in xmlCompare.Differences)
            {
                if (diffInstance.XPath == xpath)
                {
                    xmlCompare.MergeNode(diffInstance);
                    lblSelected.Text = "";
                    break;

                }
            }

            xmlCompare.UpdateDifferences();

            lblSelected.Text = "";
            UpateTextBoxes();
            //RunCompare();
            HighLightDifferences();

        }

        private void btnDiffGram_Click(object sender, EventArgs e)
        {
            XmlDocument diffGram = xmlCompare.GenerateDifferenceGraph();
            ViewXml view = new ViewXml(diffGram);
            view.Show();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveXml();
        }

        private void configureXmlEngineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CompareSettings compareSettings = new CompareSettings(xmlCompare);
            compareSettings.Show();
        }

        private void HighLightDifferences()
        {
            //remove any highlighting
            ResetColor(ntbNew.TextBox);
            ResetColor(ntbOld.TextBox);

            if (xmlCompare.Differences.Count == 0)
                return;
            
            nsMgr = xmlCompare.XmlSettings.NsMgr;

            int diff = 0;
            int missing = 0;
            foreach (DiffInstance diffInstance in xmlCompare.Differences)
            {
                SetActiveText(ntbNew.TextBox, diffInstance.NewXml);
                if (diffInstance.OldXml == null)
                {
                    //missing
                    ntbNew.TextBox.SelectionBackColor = lblMissing.BackColor;
                    missing++;

                }
                else
                {
                    SetActiveText(ntbOld.TextBox, diffInstance.OldXml);
                    //different
                    ntbNew.TextBox.SelectionBackColor = lblDifferent.BackColor;
                    ntbOld.TextBox.SelectionBackColor = lblDifferent.BackColor;
                    diff++;
                }
            }
            lblMissing.Text = missing.ToString();
            lblDifferent.Text = diff.ToString();
        }

        private void Main_Load(object sender, EventArgs e)
        {
            ntbNew.TextBox.MouseClick += new MouseEventHandler(TextBox_MouseClick);
            //ntbNew.TextBox.ReadOnly = true;
            //ntbOld.TextBox.ReadOnly = true;
        }

        private void miOpenNewXml_Click(object sender, EventArgs e)
        {
            OpenXmlFile(ntbNew);
        }

        /// <summary>
        /// Open old Xml File.
        /// </summary>
        private void miOpenOldXml_Click(object sender, EventArgs e)
        {
            OpenXmlFile(ntbOld);
        }

        /// <summary>
        /// allows the user to open an Xml File into the text box
        /// </summary>
        /// <param name="textBoxUC">the numbered text box to load the file into.</param>
        private void OpenXmlFile(NumberedTextBoxUC textBoxUC)
        {
            openFileDialog.ShowDialog(this);

            //no file selected
            if (string.IsNullOrEmpty(openFileDialog.FileName))
                return;


            string selected = openFileDialog.FileName;
            textBoxUC.TextBox.Text = File.ReadAllText(selected);
        }

        private void RunCompare()
        {
            //try to tidy memory
            GC.Collect(); //you can remove this if you want.


            //xmlCompare = new XmlCompare();

            xmlCompare.LoadOldDocXml(ntbOld.TextBox.Text);
            xmlCompare.LoadNewDocXml(ntbNew.TextBox.Text);

            xmlCompare.Compare();
            xmlFunctions = xmlCompare.XmlFunctions;

            HighLightDifferences();
        }

        private void saveProjectXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveXml();
        }

        private void SaveXml()
        {
            if (ntbOld.Text.Length == 0)
                return;

            saveFileDialog.ShowDialog(this);
            string selected = saveFileDialog.FileName;
            if (saveFileDialog.FileName == "")
            {
                return;
            }
            string path = Path.GetDirectoryName(selected);
            string ext = Path.GetExtension(selected);

            if (selected != null)
            {
                XmlFunctions.SaveToFile(xmlCompare.OldDoc, selected);
            }

        }

        /// <summary>
        /// sets the textbox Active selection to the XMLNode location.
        /// </summary>
        /// <param name="textbox">textbox to make an active selection</param>
        /// <param name="diffInstance">the node which you want selected on.</param>
        private void SetActiveText(TextBoxBase textbox, XmlNode diffInstance)
        {
            //get NewXml line number.
            int line = xmlFunctions.GetLineNumber(diffInstance, textbox.Text) - 1;
            int first = textbox.GetFirstCharIndexFromLine(line);
            int last = textbox.GetFirstCharIndexFromLine(line + 1);

            //now color the line in
            textbox.SelectionStart = first;
            textbox.SelectionLength = last - first;
        }


        /// <summary>
        /// returns the text box color to white
        /// </summary>
        /// <param name="textbox">the textbox to set its back color</param>
        private void ResetColor(RichTextBox textbox)
        {
            textbox.SelectAll();
            textbox.SelectionBackColor = lblRestColor.BackColor;
        }

        void TextBox_MouseClick(object sender, MouseEventArgs e)
        {
            try
            {
                RichTextBox tb = ntbNew.TextBox;

                if (ntbNew.TextBox.Text.Length == 0)
                    return;
                //print out the xml line.
                Point p = new Point(e.X, e.Y);
                int lineNumber = tb.GetLineFromCharIndex(tb.GetCharIndexFromPosition(p)) + 1;
                lblSelected.Text = lineNumber.ToString();

                //make sure there is a XmlNsMgr
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(ntbNew.Text);
                nsMgr = new XmlNamespaceManager(doc.NameTable);

                //Get IdNode
                string idNode = xmlCompare.XmlSettings == null ? "" : xmlCompare.XmlSettings.IdNode;
                bool xmlPossition = xmlCompare.XmlSettings == null ? false : xmlCompare.XmlSettings.XpathPosition;
                bool xmlAttributes = xmlCompare.XmlSettings == null ? false : xmlCompare.XmlSettings.XpathAttributes;
                XmlSettings settings = new XmlSettings();
                settings.IdNode = idNode;
                settings.XpathAttributes = xmlAttributes;
                settings.XpathPosition = xmlPossition;
                settings.NsMgr = nsMgr;
                XmlFunctions xmlFunc = new XmlFunctions(settings); //you do not need the XmlCompare XmlFunctions

                //update the Xpath
                string xpath = xmlFunc.GetXPath(lineNumber, ntbNew.TextBox.Text);

                if (!xpath.StartsWith("/"))
                {
                    lblSelectedXpath.Text = "";
                    return;
                }

                lblSelectedXpath.Text = xpath;

                //make sure there is an old doc before scrolling to its corrisponding node.
                if (xmlCompare.OldDoc != null)
                {

                    //now scroll to the corrisponding line. (if it exists)
                    XmlNode node = xmlCompare.OldDoc.SelectSingleNode(xpath, nsMgr);
                    if (node == null)
                        return;
                    int location = xmlFunc.GetLineNumber(node, ntbOld.TextBox.Text);

                    location = ntbOld.TextBox.GetFirstCharIndexFromLine(location - 1);
                    ntbOld.TextBox.SelectionStart = location;
                    ntbOld.TextBox.SelectionLength = 1;
                    ntbOld.TextBox.ScrollToCaret();
                }
            }
            catch (Exception)
            {
                //supress any error. for this demo project
            }
            //
            //Line: 290, Node: PropertyGroup
        }

        private void UpateTextBoxes()
        {
            ntbOld.TextBox.Text = XmlFunctions.WriteToString(xmlCompare.OldDoc);
            ntbNew.TextBox.Text = XmlFunctions.WriteToString(xmlCompare.NewDoc);

        }

    }
}
